#include "lua_ssd2828.h"
#include "ssd2828.h"
#include "tester.h"

extern struct Tester test10;
int ssd2828_VPF;
extern int ssd2828_DEBUG;

static int lua_t10_28WD(lua_State *L)
{
	printf("TODO");
	return 0;
}

static int lua_t10_28WC(lua_State *L)
{
	printf("TODO");
	return 0;
}

static int lua_t10_28WriteReg(lua_State *L)
{
	ssd2828_write_reg(&test10.ssd2828, lua_tointeger(L, 1), (lua_tointeger(L, 2) << 16) | lua_tointeger(L, 3));
	return 0;
}

static int lua_t10_28ReadReg(lua_State *L)
{
	uint16_t val = ssd2828_read_reg(&test10.ssd2828, lua_tointeger(L, 1));
	lua_pushinteger(L, val);
	return 1;
}

static int lua_t10_DcsShort(lua_State *L)
{
	ssd2828_DcsShortWrite(&test10.ssd2828, lua_tointeger(L, 1));
	return 0;
}

static int lua_t10_DcsLong(lua_State *L)
{
	ssd2828_DcsLongWrite(&test10.ssd2828, lua_tointeger(L, 1));
	return 0;
}

static int lua_t10_DcsRead(lua_State *L)
{
	int addr = lua_tointeger(L, 1);
	int cnt = lua_tointeger(L, 2);

	uint8_t par[64];
	ssd2828_DcsRead(&test10.ssd2828, addr, cnt, par);
	for (uint8_t i = 0; i < cnt; i++) {
		lua_pushinteger(L, par[i]);
	}
	return cnt;
}

static int lua_t10_GenShort(lua_State *L)
{
	ssd2828_GenericShortWrite(&test10.ssd2828, lua_tointeger(L, 1));
	return 0;
}

static int lua_t10_GenLong(lua_State *L)
{
	ssd2828_GenericLongWrite(&test10.ssd2828, lua_tointeger(L, 1));
	return 0;
}

static int lua_t10_GenRead14(lua_State *L)
{
	int addr = lua_tointeger(L, 1);
	int cnt = lua_tointeger(L, 2);

	uint8_t par[64];
	ssd2828_GenericRead(&test10.ssd2828, addr, 0, cnt, par);
	for (uint8_t i = 0; i < cnt; i++) {
		lua_pushinteger(L, par[i]);
	}
	return cnt;
}

static int lua_t10_GenRead24(lua_State *L)
{
	int para1 = lua_tointeger(L, 1);
	int para2 = lua_tointeger(L, 2);
	int len = lua_tointeger(L, 2);

	uint8_t par[64];
	for (uint8_t i = 0; i < 64; i++) {
		par[i] = 0;
	}

	ssd2828_GenericRead(&test10.ssd2828, para1, para2, len, par);
	for (uint8_t i = 0; i < len; i++) {
		lua_pushinteger(L, par[i]);
	}
	return len;
}

static int lua_t10_DsiData(lua_State *L)
{
	ssd2828_write_data(&test10.ssd2828, lua_tointeger(L, 1));
	return 0;
}

int lua_t10_ssd2828_LP(lua_State *L)
{
	ssd2828_LP(&test10.ssd2828);
	return 0;
}

int lua_t10_ssd2828_HS(lua_State *L)
{
	ssd2828_HS(&test10.ssd2828);
	return 0;
}

int lua_t10_ssd2828_VIDEO(lua_State *L)
{
	ssd2828_Video(&test10.ssd2828);
	return 0;
}

int lua_mipi_color_format(lua_State *L)
{
	int temp = lua_tointeger(L, 1);

	if ((ssd2828_VPF > 3) || (ssd2828_VPF < 0)) {
		printf("[MIPI] color depth setting: 0=16bpp, 1= 18bpp, packed, 2=18bpp loosely packed, 3=24bpp\r\n");
		return 0;
	}

	ssd2828_VPF = temp;

	return 0;
}

int lua_t10_ssd2828_DumpRegs(lua_State *L)
{
	uint16_t regvalue = 0x00;
	for (int i = 0xb0; i <= 0xf7; i++) {
		regvalue = ssd2828_read_reg(&test10.ssd2828, i);
		printf("[SSD2828] REG=%02x V=%04x\r\n", i, regvalue);
	}
	return 0;
}

int lua_t10_ssd2828_Debug(lua_State *L)
{
	int dbg = lua_tointeger(L, 1);
	test10.ssd2828.debug = dbg;
	return 0;
}

int lua_ssd2828_set_pll(lua_State *L)
{
	uint16_t r_ba_FR, r_ba_NS;
	int r_ba_MS = 1;

	int reference_freq_khz = lua_tointeger(L, 1);
	r_ba_MS = lua_tointeger(L, 2);
	r_ba_NS = lua_tointeger(L, 3);

	int real_datarate_mbps = (reference_freq_khz / 1000) * r_ba_NS / r_ba_MS;
	printf("[SSD2828] Real Datarate/lane: %d Mbps\r\n", real_datarate_mbps);

	// pll fOUT 范围
	if (real_datarate_mbps <= 125) {
		r_ba_FR = 0x00;
	} else if (real_datarate_mbps <= 250) {
		r_ba_FR = 0x40;
	} else if (real_datarate_mbps <= 500) {
		r_ba_FR = 0x80;
	} else {
		r_ba_FR = 0xc0;
	}

	int o_rBA = ((r_ba_FR | r_ba_MS) << 8) | r_ba_NS;

	ssd2828_write_reg(&test10.ssd2828, SSD2828_PCR, 0);

	ssd2828_write_reg(&test10.ssd2828, SSD2828_PLCR, o_rBA);

	ssd2828_write_reg(&test10.ssd2828, SSD2828_PCR, 1);

	return 0;
}

int lua_ssd2828_force_BABB(lua_State *L)
{
	uint16_t r_ba, r_bb;

	r_ba = lua_tointeger(L, 1);
	r_bb = lua_tointeger(L, 2);

	ssd2828_write_reg(&test10.ssd2828, SSD2828_PCR, 0);

	ssd2828_write_reg(&test10.ssd2828, SSD2828_PLCR, r_ba);
	ssd2828_write_reg(&test10.ssd2828, SSD2828_CCR, r_bb);

	ssd2828_write_reg(&test10.ssd2828, SSD2828_PCR, 1);

	printf("[SSD2828] Force set Reg0xba=%04x Reg0xbb=%04x\r\n", r_ba, r_bb);

	return 0;
}

extern uint8_t r_ba_MS;
int lua_ssd2828_set_MS(lua_State *L)
{
	/*int ms = lua_tointeger(L, 1);

	r_ba_MS = ms;

	printf("lua_ssd2828_set_MS MS=%d\r\n", ms);

	return 1;*/
	printf("TODO");
	return 0;
}

/**
 * @brief: 校验0x04和0xDA, 0xDB, 0xDC的ID是否一致
 * @note: 当前是DCS的校验
 * @param None
 * @retval: 0=Success, 1=Failed
 */
static int lua_checkMipiIdDcs(lua_State *L)
{
	unsigned char ReadCode[6];
	uint8_t ID1_val, ID2_val, ID3_val;

	if (ssd2828_DcsRead(&test10.ssd2828, 0xDA, 1, ReadCode) == 0) {
		ID1_val = ReadCode[0];
	} else {
		ID1_val = 0;
	}
	if (ssd2828_DcsRead(&test10.ssd2828, 0xDB, 1, ReadCode) == 0) {
		ID2_val = ReadCode[0];
	} else {
		ID2_val = 0;
	}
	if (ssd2828_DcsRead(&test10.ssd2828, 0xDC, 1, ReadCode) == 0) {
		ID3_val = ReadCode[0];
	} else {
		ID3_val = 0;
	}
	printf("MIPI DCS ID(DA,DB,DC): %02X %02X %02X\r\n", ID1_val, ID2_val, ID3_val);

	if (ssd2828_DcsRead(&test10.ssd2828, 0x04, 3, ReadCode) == 0) {
		printf("MIPI DCS ID(04): %02X %02X %02X\r\n", ReadCode[0], ReadCode[1], ReadCode[2]);
	}

	if ((ReadCode[0] == ID1_val) && (ReadCode[1] == ID2_val) && (ReadCode[2] == ID3_val) && ((ID1_val + ID2_val + ID3_val) > 0)) {
		printf("MIPI Driver ID Check Success\r\n");
	} else {
		printf("MIPI Driver ID Check Failed\r\n");
	}
	return 0;
}

/**
 * @brief: 校验0x04和0xDA, 0xDB, 0xDC的ID是否一致
 * @note: 当前是DCS的校验
 * @param None
 * @retval: 0=Success, 1=Failed
 */
static int lua_checkMipiIdGen(lua_State *L)
{
	unsigned char ReadCode[6];
	uint8_t ID1_val, ID2_val, ID3_val;

	if (ssd2828_GenericRead(&test10.ssd2828, 0xDA, 0, 1, ReadCode) == 0) {
		ID1_val = ReadCode[0];
	} else {
		ID1_val = 0;
	}
	if (ssd2828_GenericRead(&test10.ssd2828, 0xDB, 0, 1, ReadCode) == 0) {
		ID2_val = ReadCode[0];
	} else {
		ID2_val = 0;
	}
	if (ssd2828_GenericRead(&test10.ssd2828, 0xDC, 0, 1, ReadCode) == 0) {
		ID3_val = ReadCode[0];
	} else {
		ID3_val = 0;
	}
	printf("MIPI Gen ID(DA,DB,DC): %02X %02X %02X\r\n", ID1_val, ID2_val, ID3_val);

	if (ssd2828_GenericRead(&test10.ssd2828, 0x04, 0, 3, ReadCode) == 0) {
		printf("MIPI Gen ID(04): %02X %02X %02X\r\n", ReadCode[0], ReadCode[1], ReadCode[2]);
	}

	if ((ReadCode[0] == ID1_val) && (ReadCode[1] == ID2_val) && (ReadCode[2] == ID3_val) && ((ID1_val + ID2_val + ID3_val) > 0)) {
		printf("MIPI Driver ID Check Success\r\n");
	} else {
		printf("MIPI Driver ID Check Failed\r\n");
	}
	return 0;
}

static int lua_MIPI_PkgWrite(lua_State *L)
{
	return 0;
}

static int lua_MIPI_PkgRead(lua_State *L)
{
	return 0;
}

static int lua_MIPI_Check_Connection(lua_State *L)
{
	return 0;
}

// ssd2828
struct luaL_Reg functionExport_ssd2828[] = {
    {"t10_28WD", lua_t10_28WD},
    {"t10_28WC", lua_t10_28WC},
    {"t10_28WriteReg", lua_t10_28WriteReg},
    {"t10_28ReadReg", lua_t10_28ReadReg},
    {"DcsS", lua_t10_DcsShort},
    {"DcsL", lua_t10_DcsLong},
    {"DcsR", lua_t10_DcsRead},
    {"GenS", lua_t10_GenShort},
    {"GenL", lua_t10_GenLong},
    {"GenR14", lua_t10_GenRead14},
    {"GenR24", lua_t10_GenRead24},
    {"DsiD", lua_t10_DsiData},
    {"MIPI_LP", lua_t10_ssd2828_LP},
    {"MIPI_HS", lua_t10_ssd2828_HS},
    {"MIPI_VIDEO", lua_t10_ssd2828_VIDEO},
    {"MIPI_Color_Format", lua_mipi_color_format},
    {"ssd2828_DumpRegs", lua_t10_ssd2828_DumpRegs},
    {"ssd2828_Debug", lua_t10_ssd2828_Debug},
    {"ssd2828_set_pll", lua_ssd2828_set_pll},
    {"ssd2828_force_BABB", lua_ssd2828_force_BABB},
    {"ssd2828_set_MS", lua_ssd2828_set_MS},
    {"checkMipiIdDcs", lua_checkMipiIdDcs},
    {"checkMipiIdGen", lua_checkMipiIdGen},
    {"MIPI_PkgWrite", lua_MIPI_PkgWrite},
    {"MIPI_PkgRead", lua_MIPI_PkgRead},
    {"MIPI_Check_Connection", lua_MIPI_Check_Connection},
    {NULL, NULL},
};